<!--
 * @LastEditTime: 2023-12-08 09:53:40
 * @FilePath: \bdcar-net\src\views\trajectoryMonitor\trajectoryTrack\index.vue
 * @Description: 轨迹跟踪-打开的新弹窗页面
-->
<template>
  <div class="app-container" v-loading="mapLoading">
    <!-- 地图 -->
    <div id="TT_container"></div>

    <!-- 左上-查询条件窗体 -->
    <ul class="search-dom">
      <li>
        <div class="background-dom">
          <el-date-picker class="track-timepicker" v-model="query.queryTime" value-format="YYYY-MM-DD HH:mm:ss"
            :default-time="[new Date(2000, 1, 1, 0, 0, 0),
            new Date(2000, 2, 1, 23, 59, 59)]" type="datetimerange" :clearable="false" popper-class="noShowClear"
            range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :shortcuts="shortcuts"
            :disabled-date="disabledDate" @calendar-change="handleChange">
          </el-date-picker>
        </div>
        <div class="background-dom">
          <div class="search-title">公司：</div>
          <el-tree-select v-model="query.companyId" placeholder="请选择" clearable :data="companyOptions"
            :expand-on-click-node="false" :render-after-expand="false" check-strictly :props="{ label: 'label' }"
            node-key="id" filterable class="search-input" @change="companyChangeHandle" />
          <div class="search-title" style="margin-left:auto">车牌号：</div>
          <el-select @change="getCarDetail" @clear="query.companyId = null" class="search-input" clearable
            v-model="query.deviceNo" filterable remote reserve-keyword placeholder="请输入关键词"
            :remote-method="querySearchAsync" :loading="loading">
            <el-option v-for=" item  in  searchOptions " :key="item.value" :label="item.label" :value="item.value">
            </el-option>
          </el-select>
          <!-- 查询 -->
          <el-button type="primary" @click="getTrackList" class="search-btn">
            <svg-icon icon-class="search" />
          </el-button>
        </div>
      </li>
      <li>
        <div class="trackControl-top">
          <el-checkbox v-model="switchValue" class='my-checkbox' @change="updateInfoWindos">气泡</el-checkbox>
          <el-checkbox v-model="pointsCheck" class='my-checkbox' @change="showTrachPoints">轨迹点</el-checkbox>
          <el-select v-model="times" style="width:140px;margin-left:auto;" @change="changeSpd" filterable>
            <el-option v-for="item in timesOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </el-select>
        </div>
        <div class="trackControl-mid">
          <svg-icon icon-class="play" @click="navgControl('start')" title="播放" v-if="!isPlay" />
          <svg-icon icon-class="pause" @click="navgControl('pause')" title="暂停" v-else />
          <svg-icon icon-class="stop" @click="navgControl('stop')" title="停止" />
          <div class="timeText">00:00:00</div>
          <el-slider v-model="sliderVal" class="slider" :show-tooltip="false" :step="1" @change="sliderChange" :min='1'
            :max="dealAllList.length == 0 ? 1 : dealAllList.length"></el-slider>
          <div class="timeText">{{ totalTime }}</div>
        </div>
      </li>
    </ul>

    <!-- 工具栏 -->
    <mapTool ref="myMapTool" class="track-tool" :show="true" :map="reactMap.map" :fenceFormHandle="fenceFormHandle">
    </mapTool>

    <!-- 右上-轨迹相关其他功能 -->
    <div class="track-tool-right">
      <!-- 工具栏 -->
      <div @click="trackToolHandle('statisticState')" class="tool-btn" :class="{ active: trackToolParam.statisticState }">
        <i class="iconfont icon-status"></i>
        状态
      </div>
      <div @click="trackToolHandle('speedData')" class="tool-btn" :class="{ active: trackToolParam.speedData }">
        <i class="iconfont icon-speedLine"></i>
        速度
      </div>
      <div @click=" trackToolHandle('stopInfo');" class="tool-btn" :class="{ active: trackToolParam.stopInfo }">
        <i class="iconfont icon-parking"></i>
        停留
      </div>
      <div @click="trackToolHandle('alarmData')" class="tool-btn" :class="{ active: trackToolParam.alarmData }">
        <i class="iconfont icon-warning"></i>
        报警
      </div>
      <div @click="trackToolHandle('trackData')" class="tool-btn" :class="{ active: trackToolParam.trackData }">
        <i class="iconfont icon-report"></i>
        报表
      </div>
      <template v-if="!isWindow">
        <el-divider direction="vertical" style="margin-top: 2px;" />
        <div @click="openInNewWindow" class="new-window-btn">
          独立页面打开
          <el-icon>
            <ArrowRight />
          </el-icon>
        </div>
      </template>
    </div>

    <div class="track-tool-list">
      <!-- 状态 -->
      <div class="statistics-line-dom" v-show="trackToolParam.statisticState">
        <div class="top-dom">
          <i class="iconfont icon-status"></i>
          <span>状态</span>
          <el-icon @click="trackToolParam.statisticState = false">
            <Close />
          </el-icon>
        </div>
        <div class="content">
          <div class="statistics-info" v-for="(v, i) in trackStatisticsList" :key="v.prop"
            :style="{ width: i == 6 || i == 7 ? '100%' : '180px' }">
            <span style="margin-right: 10px;">{{ v.name }}:</span>
            <span style="color: #FF7E36;">{{ trackStatistics[v.prop] }} </span>
            {{ v?.unit }}
          </div>
        </div>
      </div>
      <!-- 速度 -->
      <div class="speed-line-dom" v-show="trackToolParam.speedData">
        <div class="top-dom">
          <i class="iconfont icon-speedLine"></i>
          <span>速度</span>
          <el-icon @click="trackToolParam.speedData = false">
            <Close />
          </el-icon>
        </div>
        <div class="content">
          <LineChart echartsClass="speedLine" :echartsData='speedObj' ref="lineChart" />
        </div>
      </div>
    </div>

    <!-- 报表 -->
    <div class="track-report-form" v-if="trackToolParam.trackData">
      <div class="top-dom">
        <i class="iconfont icon-report"></i>
        <span>报表</span>
        <div class="right-dom">
          <div class="export-btn" @click="exportList('trackData')">导出</div>
          <el-icon @click="trackToolHandle('trackData')">
            <Close />
          </el-icon>
        </div>
      </div>
      <div class="bot-body">
        <virtualTable style="width:100%;height:100%;" :columns="trackDataItems" :data="dealAllList" :click="showTrackData"
          :rowCancel="closePop">
          <template #rowItem="{ column, rowData, rowIndex }">
            <span v-if="column.key === 'index'">{{ rowIndex + 1 }}</span>
            <span v-else :title="rowData[column.key]" class="overflow-text">{{ rowData[column.key] }}</span>
          </template>
        </virtualTable>
      </div>
    </div>
    <!-- 停留信息 -->
    <div class="track-report-form" v-else-if="trackToolParam.stopInfo">
      <div class="top-dom">
        <i class="iconfont icon-parking"></i>
        <span>停留</span>
        <div class="right-dom">
          <div class="export-btn" @click="exportList('stopInfo')">导出</div>
          <el-icon @click="trackToolHandle('stopInfo')">
            <Close />
          </el-icon>
        </div>
      </div>
      <div class="bot-body" style="flex-direction: column;">
        <ul class="top-nav">
          <li :class="{ active: trackDetailParam.trackInfo === '' }" @click="trackDetailParam.trackInfo = ''">全部</li>
          <li :class="{ active: trackDetailParam.trackInfo === 'drive' }" @click="trackDetailParam.trackInfo = 'drive'">
            移动</li>
          <li :class="{ active: trackDetailParam.trackInfo === 'stop' }" @click="trackDetailParam.trackInfo = 'stop'">
            停留
          </li>
        </ul>
        <virtualTable style="height:calc(100% - 40px);width:100%;" :columns="trackInfoItems" :data="trackInfoList"
          :click="showPeriodTrac" :rowCancel="cancelPeriodTrac" active-key="startT">
          <template #rowItem="{ column, rowData, rowIndex }">
            <span v-if="column.key === 'index'">{{ rowIndex + 1 }}</span>
            <span v-else-if="column.key === 'actionStr'">
              <div :class="rowData[column.key] == '停留' ? 'stop-tab' : 'drive-tab'"></div>
              {{ rowData[column.key] }}
            </span>
            <span v-else :title="rowData[column.key]" class="overflow-text">{{ rowData[column.key] }}</span>
          </template>
        </virtualTable>
      </div>
    </div>
    <!-- 报警信息 -->
    <div class="track-report-form" v-else-if="trackToolParam.alarmData" v-loading="alarmLoading">
      <div class="top-dom">
        <i class="iconfont icon-warning"></i>
        <span>报警</span>
        <div class="right-dom">
          <div class="export-btn" @click="exportList('alarmData')">导出</div>
          <el-icon @click="trackToolHandle('alarmData')">
            <Close />
          </el-icon>
        </div>
      </div>
      <div class="bot-body">
        <ul class="left-nav">
          <template v-for="(v, i) in alarmOptions" :key="v.value">
            <li :class="{ active: trackDetailParam.alarmData === v.value }" @click="trackDetailParam.alarmData = v.value"
              v-if="v.number > 0 || i == 0" :title="v.label">
              <span class="label-str overflow-text">{{ v.label }}</span>
              <span class="number-str">{{ v.number }}</span>
            </li>
          </template>
        </ul>
        <virtualTable style="width:calc(100% - 166px);height:100%;display: inline-block;" :columns="alarmDataItems"
          :data="filterAlarmList" :click="showAlarmDetail" :rowCancel="closePop" active-key="id">
          <template #rowItem="{ column, rowData, rowIndex }">
            <span v-if="column.key === 'index'">{{ rowIndex + 1 }}</span>
            <span v-else-if="column.key === 'operation'">
              <div @click="showFile(rowData)" class="other-btn" v-show="rowData.amc">
                证据
              </div>
            </span>
            <span v-else :title="rowData[column.key]" class="overflow-text">{{ rowData[column.key] }}</span>
          </template>
        </virtualTable>
      </div>
    </div>

    <!-- 证据 -->
    <el-dialog v-model="evidenceShow" width="906px" top="15vh" destroy-on-close>
      <template #header>
        <div class="dialog-title">
          <div class="cicle"></div>
          <span>证据</span>
        </div>
      </template>
      <div style="height:500px;background:black">
        <video :src="fileList.video" controls autoplay muted style="width:640px;height:500px;float:left"></video>
        <div class="img-dom">
          <img :src="fileList.image[0]" v-if="fileList.image[0]">
          <div class="noImage" v-else>
            <span>暂无图片</span>
          </div>
        </div>
        <div class="img-dom">
          <img :src="fileList.image[1]" v-if="fileList.image[1]">
          <div class="noImage" v-else>
            <span>暂无图片</span>
          </div>
        </div>
        <div class="img-dom">
          <img :src="fileList.image[2]" v-if="fileList.image[2]">
          <div class="noImage" v-else>
            <span>暂无图片</span>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 围栏新增和编辑 -->
    <div v-show="editFormShow" class="fence-form">
      <div class="top-dom">
        <svg-icon icon-class="fence" class="iconfont" />
        <span>{{ title }}</span>
        <el-icon @click="cancel">
          <Close />
        </el-icon>
      </div>
      <el-form ref="fenceRef" :model="form" :rules="rules" label-width="80px" style="padding: 0 20px;margin-top:16px">
        <el-form-item v-for="v in form.type == 2 ? fenceItems : lineItems" :key="v.prop" :label="v.name" :prop="v.prop">
          <el-input v-if="v.type == 'input'" v-model.trim="form[v.prop]" :disabled="!needEdit"></el-input>
          <el-tree-select v-else-if="v.type == 'treeSelect'" v-model="form[v.prop]" clearable :data="sel_option[v.prop]"
            :expand-on-click-node="false" :render-after-expand="false" check-strictly :props="{ label: 'label' }"
            node-key="id" filterable placeholder="" style="width: 320px;" :disabled="!needEdit" />
          <el-input v-else-if="v.type == 'textarea'" readonly v-model="form[v.prop]" type="textarea" :disabled="!needEdit"
            placeholder="绘制图形后自动填充" />
        </el-form-item>
      </el-form>
      <div class="dialog-footer">
        <el-button type="primary" @click="submitForm" v-if="needEdit">确 定</el-button>
        <el-button type="primary" @click="editFence" v-else>修 改</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </div>
  </div>
</template>
<script lang="tsx">
declare const L: any;
import { getTrackByid, getLastGpsByid } from "../../../api/trajectoryMonitor/trajectoryTrack";
import { saveElectricFence, updateElectricFence } from "../../../api/comlbs/electricFence";
import { treeDept } from "../../../api/system/dept";
import mapPop from './trackPop.vue';
import dayjs from 'dayjs';
import { initMap, addLotsOfPoints } from '../../../utils/map/leafletMap';
import "@/utils/map/MovingMarker";
import { ref, Ref, createApp } from "vue";
import mapTool from "../../../components/map/mapTool.vue"
import request from '../../../utils/request'
import virtualTable from '../../../components/virtualTable/index.vue'
import LineChart from "../../../components/Echart/LineChart.vue"
import { getAlarmTypeAll } from "../../../api/alarmProcess/alarmProcess";
import { getMinAdsBy84Poi } from "../../../utils/map/leafletMap"
let map: any = null;
let nodeIndex: any = [];//存储停留点位的index
let allList: any = [];//存储小车轨迹原始数据
let newLatlngs: any = [];
//管理地图存在的覆盖物以及刷新或删除
let mapLayer: any = {
  navgtr: null, //小车标注(巡航器)
  routeLine: null,//地图展示的小车轨迹
  realRouteLine: null,//小车走过的线
  trackShowLine: null,//地图展示的某段小车轨迹
  alarmLayer: null,//报警数据图层
  sPointLayer: null,//轨迹起点图层
  ePointLayer: null,//轨迹重点图层
  stopLayer: null,//停留点图层
  newTrack: null,//纠正的轨迹线
  trackPointsLayer: null,//轨迹点集合图层
};
let selectData = null //当前选中日历日期
let isPlayEnd: any = false;//小车是否跑到了终点
let selectEquip: any = null;//被选中的车数据
const stopTime: any = 2;//停留判定时长（min）

//围栏相关
let drawObj = null;//绘制围栏的对象
let editDrawObj = null;//编辑围栏的对象
let drawLayer = null;
let mapAddListener = false; //地图有没有绑定draw事件
const editGraphOption = {
  touchIcon: new L.DivIcon({
    iconSize: new L.Point(4, 4),
    className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
  }),
}

export default {
  name: "TrajectoryTrack",
  data() {
    const reactMap: any = ref({ map: null });
    const isPlay: any = ref(false);
    const pointsCheck: any = ref(false);
    const switchValue: any = ref(true);
    const totalTime: any = ref("00:00:00");
    const sliderVal: any = ref(0);
    const times: any = ref(10);
    const tableActive: any = ref(-1);
    const timesOptions: any = ref([
      { value: 20, label: '播放速度(极速)' },
      { value: 10, label: '播放速度(快速)' },
      { value: 1, label: '播放速度(正常)' },
    ]);

    const dealAllList: any = ref([]);
    const timeInfoList: any = ref([]);
    const nowCarPointIndex: any = ref(0);
    const shortcuts: Ref<any> = ref([
      {
        text: "最近6小时",
        value() {
          const end = new Date();
          const start = new Date();
          start.setTime(start.getTime() - 3600 * 1000 * 6 * 1);
          return [start, end];
        },
      },
      {
        text: "最近12小时",
        value() {
          const end = new Date();
          const start = new Date();
          start.setTime(start.getTime() - 3600 * 1000 * 12 * 1);
          return [start, end];
        },
      },
      {
        text: "最近一天",
        value() {
          const end = new Date();
          const start = new Date();
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
          return [start, end];
        },
      }
    ]);
    const query: any = ref({
      queryTime: [],
      deviceNo: null,
      companyId: null,
      alarmType: null,
    });
    const alarmActive: Ref<any> = ref(-1);
    const companyOptions: Ref<any> = ref([]);
    const searchOptions: Ref<any> = ref([]);
    const alarmOptions: Ref<any> = ref([]);
    const alarmOptionsAll: Ref<any> = ref([]);
    const loading: Ref<any> = ref(false);
    const alarmLoading: Ref<any> = ref(false);
    const mapLoading: Ref<any> = ref(false);
    const mapPop: Ref<any> = ref(null);
    const alarmList: Ref<any> = ref([]);
    const trackStatisticsList: Ref<any> = ref([
      { name: "行驶时长", prop: "driveTime" },
      { name: "停留时长", prop: "stopTime" },
      { name: "轨迹里程", prop: "totalKm", unit: "km" },
      { name: "轨迹点", prop: "count" },
      { name: "平均速度", prop: "averageSpd", unit: "km/h" },
      { name: "最高速度", prop: "maxSpd", unit: "km/h" },
      { name: "开始时间", prop: "startTime" },
      { name: "结束时间", prop: "endTime" },
    ]);
    const trackStatistics: Ref<any> = ref({
      averageSpd: 0,
      maxSpd: 0,
      totalKm: 0,
      driveTime: "00:00:00",
      stopTime: "00:00:00",
    });
    const trackDetailParam: Ref<any> = ref({
      trackInfo: '',
      alarmData: '',
    });
    const trackDataItems: Ref<any> = ref([
      { key: "index", title: "序号", width: 60 },
      { key: "gdt", title: "定位时间", width: 150 },
      { key: "spd", title: "速度(km/h)", width: 90 },
      { key: "totalKm", title: "行驶里程(km)", width: 110 },
      { key: "location", title: "定位位置", width: null },
      { key: "satelliteCount", title: "卫星数", width: 60 },
      { key: "lng", title: "定位经度", width: 90 },
      { key: "lat", title: "定位纬度", width: 90 },
    ]);
    const trackInfoItems: Ref<any> = ref([
      { key: "index", title: "序号", width: 64 },
      { key: "actionStr", title: "轨迹状态", width: 80 },
      { key: "hhmmss", title: "时长", width: 80 },
      { key: "totalKm", title: "行驶里程(km)", width: 110 },
      { key: "startT", title: "开始时间", width: 150 },
      { key: "endT", title: "结束时间", width: 150 },
      { key: "startPlace", title: "开始位置", width: null },
      { key: "endPlace", title: "结束位置", width: null },
    ]);
    const alarmDataItems: Ref<any> = ref([
      { key: "index", title: "序号", width: 64 },
      { key: "alarmTypeName", title: "报警类型", width: 160 },
      { key: "startTime", title: "报警时间", width: 160 },
      { key: "spd", title: "速度(km/h)", width: 120 },
      { key: "address", title: "定位位置", width: null },
      { key: "operation", title: "操作", width: 80 },
    ]);
    const lastPlayStatus: Ref<any> = ref(false);
    const timer = ref(null)
    const myRequire = (str) => {
      return new URL(`../../../assets/img/${str}`, import.meta.url).href
    }
    const trackToolParam = ref({
      stopInfo: false,
      trackData: false,
      alarmData: false,
      statisticState: false,
      speedData: false,
    });
    const speedObj = ref({})
    const isWindow = ref(false);
    const evidenceShow: Ref<any> = ref(false);
    const fileList: Ref<any> = ref({
      video: '',
      image: [],
    });

    // 围栏相关
    const editFormShow = ref(false);
    const form = ref({
      type: null,
    });
    const title = ref("");
    const fenceItems = ref([
      { name: '所属公司', prop: "companyId", type: 'treeSelect' },
      { name: '围栏名称', prop: "name", type: 'input' },
      { name: '围栏地点', prop: "address", type: 'textarea' },
    ])
    const lineItems = ref([
      { name: '所属公司', prop: "companyId", type: 'treeSelect' },
      { name: '线路名称', prop: "name", type: 'input' },
      { name: '线路地点', prop: "address", type: 'textarea' },
    ])
    const sel_option = ref({ companyId: [] })
    treeDept().then(res => {
      sel_option.value.companyId = res.data
    })
    const rules = ref({
      name: [
        { required: true, message: "请输入围栏名称", trigger: "blur" },
        { required: true, message: "请输入围栏名称", trigger: "change" },
      ],
      address: [
        { required: true, message: "请完成图形绘制", trigger: "blur" },
      ],
      companyId: [
        { required: true, message: "请选择", trigger: "input" },
      ],
    })
    const needEdit = false;
    return {
      fenceItems, lineItems, sel_option, editFormShow, form, title, rules, needEdit,
      fileList,
      evidenceShow,
      tableActive,
      speedObj,
      trackToolParam,
      myRequire,
      reactMap,
      isPlay,//用来判定是否在播放轨迹
      totalTime, //已经走了的时间
      sliderVal, //进度条滑动速度
      times, //几倍速度播放
      timesOptions,
      dealAllList,//存储小车全部数据,处理后
      timeInfoList,//时间轴数据 
      newLatlngs,
      nowCarPointIndex, //存储当前小车所在点的序号
      query,
      switchValue,
      pointsCheck,
      shortcuts,
      alarmActive,//判定高亮
      companyOptions,//公司下拉选项     
      searchOptions,
      alarmOptions,//报警类型下拉
      alarmOptionsAll,//报警类型下拉
      loading,
      mapLoading,
      mapPop,

      alarmList,//报警数据列表
      trackStatisticsList,
      trackStatistics,
      trackDetailParam,
      trackDataItems,
      trackInfoItems,
      alarmDataItems,
      lastPlayStatus,//记录上一个播放状态
      alarmLoading,
      timer,
      isWindow,//是不是弹窗页面
    };
  },
  created() {
    this.query.queryTime[0] = dayjs(new Date()).format("YYYY-MM-DD 00:00:00");
    this.query.queryTime[1] = dayjs(new Date()).format("YYYY-MM-DD 23:59:59");

    this.alarmOptionsAll = []
    getAlarmTypeAll().then(resp => {
      resp.data.forEach(p => {
        this.alarmOptionsAll.push({ label: p.name, value: p.type, number: 0 })
      })
    })
  },
  mounted() {
    // 从浏览器中获取接口，如果参数存在则是弹窗，否则是内部页面
    const params: any = {}
    const paramsStr = window.location.search.split('?')[1]
    if (paramsStr) {
      const paramsArr = paramsStr.replace(/&|=/g, ' ').split(' ')
      for (let i = 0; i < paramsArr.length / 2; i++) {
        const value = paramsArr[i * 2 + 1]
        params[paramsArr[i * 2]] = value === 'true' ? true : value === 'false' ? false : value
      }
      this.query.deviceNo = params.deviceNo
      this.query.companyId = params.companyId
      this.query.alarmType = params.alarmType || null
      this.query.queryTime[0] = decodeURIComponent(params.queryTime).split(',')[0].replace('+', ' ')
      this.query.queryTime[1] = decodeURIComponent(params.queryTime).split(',')[1].replace('+', ' ')
      this.searchOptions = [{
        value: params.deviceNo,
        label: decodeURIComponent(params.numberPlate),
      }];
      this.getCarDetail();
      this.isWindow = true;
    }

    let _this = this;
    //dom生成以后才能挂载地图
    initMap("TT_container").then(_map => {
      // 引入 Vue 组件构造器实例化
      let mapPopContent = createApp(mapPop)
      let parent = document.createElement('div');
      let component: any = mapPopContent.mount(parent);
      component.parent = _this;
      // 挂载组件
      _this.MapPopContent = component;
      map = _map

      map.on(L.Draw.Event.CREATED, this.drawCreateBack);
      map.on(L.Draw.Event.EDITVERTEX, () => {
        this.drawCreateBack({ layer: drawLayer.getLayers()[0] })
      });

      this.reactMap.map = map
      if (paramsStr) this.getTrackList();
    })

    //获取公司下拉树
    treeDept().then(res => {
      _this.companyOptions = res.data
    })
  },
  components: {
    mapTool, virtualTable, LineChart
  },
  computed: {
    trackInfoList() {
      let list = this.timeInfoList.filter(v => {
        return v.action.includes(this.trackDetailParam.trackInfo)
      });
      return list
    },
    filterAlarmList() {
      if (this.trackDetailParam.alarmData === '') return this.alarmList
      return this.alarmList.filter(v => v.alarmType === this.trackDetailParam.alarmData)
    },
  },
  methods: {
    // 绘制方法的回调
    drawCreateBack(e) {
      let points = [], _this = this, _center = [];
      if (this.form.type == 3) {
        points = e.layer.getLatLngs();
      } else if (this.form.type == 2) {
        points = e.layer.getLatLngs()[0];
      }
      // 获取质心
      function getPolygonAreaCenter(points) {
        function Area(p0, p1, p2) {
          let area = 0.0;
          area = p0[0] * p1[1] + p1[0] * p2[1] + p2[0] * p0[1] - p1[0] * p0[1] - p2[0] * p1[1] - p0[0] * p2[1];
          return area / 2;
        }
        let sum_x = 0;
        let sum_y = 0;
        let sum_area = 0;

        if (points.length == 2) {
          return [(points[0][0] + points[1][0]) / 2, (points[0][1] + points[1][1]) / 2]
        }

        let p1 = points[1],
          p2, area;
        for (let i = 2; i < points.length; i++) {
          p2 = points[i];
          area = Area(points[0], p1, p2);
          sum_area += area;
          sum_x += (points[0][0] + p1[0] + p2[0]) * area;
          sum_y += (points[0][1] + p1[1] + p2[1]) * area;
          p1 = p2;
        }
        let xx = sum_x / sum_area / 3;
        let yy = sum_y / sum_area / 3;
        return [xx, yy];
      }
      // 获取位置信息
      function getGraphAddress(point) {
        let query = {
          lng: point[0],//城市权重优先
          lat: point[1]
        }
        getMinAdsBy84Poi(query).then(res => {
          if (res.code == 200) {
            _this.form.address = res.data
          }
        })
      }
      _center = getPolygonAreaCenter(points.map(v => [v.lng, v.lat]))
      getGraphAddress(_center)
      let isNewGraph = true;
      if (this.form.xyWgs84) {
        isNewGraph = false;
      }
      this.form.xyWgs84 = points.map(v => { return { lng: v.lng, lat: v.lat } })
      if (isNewGraph) this.editDrawLayer()
    },
    // 围栏提交
    submitForm() {
      this.$refs["fenceRef"].validate(valid => {
        if (valid) {
          switch (this.form.type) {
            case 2: { //围栏
              this.form.xyWgs84 = drawLayer.getLayers()[0].getLatLngs()[0]
              break;
            }
            case 3: { // 线路
              this.form.xyWgs84 = drawLayer.getLayers()[0].getLatLngs()
              break;
            }
          }
          let fun = null
          if (this.form.id) {
            fun = updateElectricFence
          } else {
            fun = saveElectricFence
          }
          fun(this.form).then(res => {
            if (res.code == 200) {
              this.$modal.msgSuccess("操作成功!");
              // 如果已经打开围栏图层，则需要刷新一下
              if (this.form.type == 2 && this.$refs.myMapTool.layerCheck.fence) {
                this.$refs.myMapTool.initLayer(2, true)
              }
              if (this.form.type == 3 && this.$refs.myMapTool.layerCheck.road) {
                this.$refs.myMapTool.initLayer(3, true)
              }
            }
            this.cancel();
          })
        }
      });
    },
    // 围栏取消
    cancel() {
      this.editFormShow = false;
      if (drawObj) {
        drawObj.disable();
        drawObj = null;
      }
      if (editDrawObj) {
        editDrawObj.disable();
        editDrawObj = null;
      }
      drawLayer.clearLayers();
    },
    // 处理围栏表单-新增-查看
    fenceFormHandle(editForm, isAdd = true) {
      // 当前表单处于编辑状态的时候不能再打开表单
      if (this.needEdit && this.editFormShow) return
      this.title = editForm.type == 2 ? '围栏' : '线路';
      this.editFormShow = true;
      this.closePop();
      if (mapAddListener == false) {
        mapAddListener = !mapAddListener
      }
      this.form = editForm;
      this.needEdit = isAdd;
      if (isAdd) {
        this.form.companyId = this.query.companyId;
        this.startDraw(this.form.type);
      }
    },
    // 处理围栏表单-编辑
    editFence() {
      this.needEdit = !this.needEdit;
      this.editDrawLayer();
    },
    // 新增围栏-开始绘制
    startDraw(editType) {
      if (drawObj) {
        drawObj.disable();
        drawObj = null;
      }
      switch (editType) {
        case 2: { //围栏
          drawObj = new L.Draw.Polygon(map, editGraphOption);
          break;
        }
        case 3: { // 线路
          drawObj = new L.Draw.Polyline(map, editGraphOption);
          break;
        }
      }
      // 启动
      drawObj?.enable();
    },
    // 绘制围栏编辑图层
    editDrawLayer() {
      drawLayer = L.featureGroup().addTo(map)
      let _graph;
      const graphParam = {
        fillColor: '#0066FF',// 多边形填充颜色
        weight: 2, // 线条宽度，默认为 1
        color: '#0066FF', // 线条颜色
      };
      switch (this.form.type) {
        case 2:
          _graph = L.polygon(this.form.xyWgs84, { ...graphParam });
          break;
        case 3:
          _graph = L.polyline(this.form.xyWgs84, { ...graphParam });
          break;
      }
      drawLayer.addLayer(_graph);
      editDrawObj = new L.EditToolbar.Edit(map, { featureGroup: drawLayer, ...editGraphOption });
      editDrawObj.enable();
    },
    openInNewWindow() {
      let _query = this.query;
      if (!_query.deviceNo || !_query.companyId) {
        this.$modal.msgWarning("请填写公司和设备以后再试");
        return
      }
      window.open(window.location.origin + "/trajectoryTrack?numberPlate=" + selectEquip.numberPlate + "&deviceNo=" + _query.deviceNo + "&companyId=" + _query.companyId + "&queryTime=" + _query.queryTime)
    },
    showFile(row) {
      this.fileList = {
        video: '',
        image: [],
      };
      request({
        url: "/comlbs/reportStatistics/deviceAlarm/evidence",
        method: "post",
        params: {
          alarmCode: row.amc,
        }
      }).then((res: any) => {
        this.evidenceShow = true
        if (res.code == 200) {
          res.data.forEach(el => {
            if (el.fte == 2)
              //@ts-ignore
              this.fileList.video = import.meta.env.VITE_APP_BASE_API + el.pth
            else
              //@ts-ignore
              this.fileList.image.push(import.meta.env.VITE_APP_BASE_API + el.pth)
          })
        }
      })
    },
    cancelPeriodTrac(data: any) {
      if (data.action == 'stop') {
        this.closePop()
      } else {
        if (mapLayer.trackShowLine) {
          map.removeLayer(mapLayer.trackShowLine);
        }
      }
    },
    // 选中日历日期的回调 val:[起始日期，结束日期]
    handleChange(val) {
      selectData = val
      if (val[1]) selectData = null
    },
    disabledDate(time) {
      // 是否限制的判断条件
      if (selectData) {
        // 这里就是限制的关键，超过三天禁选
        let before = dayjs(selectData[0]).add(-7, 'day').unix();
        let after = dayjs(selectData[0]).add(7, 'day').unix();
        return time.getTime() / 1000 > after || time.getTime() / 1000 < before
      } else {
        return false
      }
    },
    // 报表导出
    exportList(param) {
      if (param == 'stopInfo') {
        this.downloadByJSON('/comlbs/realtimePositioning/trajectoryExport', this.trackInfoList, `轨迹信息-${selectEquip?.numberPlate}_${dayjs(new Date()).format("YYYY-MM-DD_HH:mm:ss")}.xlsx`);
      } else if (param == 'alarmData') {
        this.downloadByJSON('/comlbs/realtimePositioning/alarmExport', {
          startTime: this.query.queryTime[0],
          endTime: this.query.queryTime[1],
          dvo: this.query.deviceNo
        }, `报警数据-${selectEquip?.numberPlate}_${dayjs(new Date()).format("YYYY-MM-DD_HH:mm:ss")}.xlsx`);
      } else if (param == "trackData") {
        this.downloadByJSON('/comlbs/realtimePositioning/trajectory/originalDataExport', this.dealAllList, `${selectEquip?.numberPlate}(${this.query.queryTime[0]}至${this.query.queryTime[1]})-报表数据.xlsx`);
      }
    },
    trackToolHandle(paramStr) {
      let _this = this;
      this.trackToolParam[paramStr] = !this.trackToolParam[paramStr];
      function handleByParam(param) {
        switch (param) {
          case 'stopInfo':
            if (_this.trackToolParam.stopInfo) _this.showStopPoints();
            else {
              _this.closeStopLayer();
              if (!_this.trackToolParam.alarmData) _this.closePop()
            }
            break;
          case 'alarmData':
            if (!_this.query.deviceNo) return
            if (_this.trackToolParam.alarmData) _this.getAlarmList();
            else {
              _this.closeAlarmLayer();
              if (!_this.trackToolParam.stopInfo) _this.closePop()
            }
            break;
          case 'trackData':
            _this.pointsCheck = _this.trackToolParam[param];
            _this.showTrachPoints();
            break;
          case 'statisticState':
            break;
          case 'speedData':
            if (!_this.trackToolParam[param]) return
            _this.speedObj = {
              title: "",
              xAxisData: [],
              yAxisData: [],
            }
            allList.forEach(v => {
              _this.speedObj.yAxisData.push(v.spd)
              _this.speedObj.xAxisData.push(v.gdt)
            })
            _this.$nextTick(() => {
              _this.$refs.lineChart.resize();
            })
            break;
        }
      }
      // trackData stopInfo alarmData 同一时间只能存在一种,选中一个取消其他两个
      let list = ["trackData", "stopInfo", "alarmData"];
      if (list.includes(paramStr)) {
        list.forEach(v => {
          if (v != paramStr && this.trackToolParam[v]) {
            this.trackToolParam[v] = false;
            handleByParam(v)
          }
        })
      }
      handleByParam(paramStr);
    },
    // 获取设备对应公司
    getCarDetail() {
      if (!this.query.deviceNo) return
      getLastGpsByid(this.query.deviceNo).then(res => {
        if (res.data.code == 1) return
        selectEquip = res.data;
        this.query.companyId = res.data.companyId;
      })
    },
    companyChangeHandle() {
      this.query.deviceNo = null;
    },
    showStopPoints() {
      let _list: any = [], _this = this;
      this.timeInfoList.forEach(v => {
        if (v.action == 'stop') {
          let _point = allList[v.endIndex]
          // 添加停留点
          let marker: any = L.marker(_point, {
            icon: L.icon({
              iconUrl: this.myRequire('track/parkPoint.png'),
              iconAnchor: [18, 18]
            }),
          }).on('click', function (ev) {
            _this.showPopup({ ...v, lng: _point.lng, lat: _point.lat }, "parkPoint", "停留点")
          });
          _list.push(marker);
        }
      })
      mapLayer.stopLayer = L.featureGroup(_list).addTo(map);
    },
    showAlarmDetail(row) {
      if (this.alarmActive == row.id) {
        this.alarmActive = -1
        this.closePop()
        return
      }
      this.alarmActive = row.id;
      map.flyTo(row, 18, { animate: false })
      this.showPopup(row, "alarmPoint", "报警点")
    },
    showTrackData(row, columnIndex) {
      map.flyTo(row, 16, { animate: false })
      this.showPopup(row, "trackPoint", "轨迹点")
    },
    closeStopLayer() {
      if (mapLayer.stopLayer) {
        mapLayer.stopLayer.removeFrom(map)
        mapLayer.stopLayer = null;
      }
    },
    closeAlarmLayer() {
      if (mapLayer.alarmLayer) {
        mapLayer.alarmLayer.removeFrom(map)
        mapLayer.alarmLayer = null;
      }
    },
    getAlarmList() {
      let _this = this;
      this.closeAlarmLayer();
      this.alarmLoading = true
      request({
        url: "/comlbs/realtimePositioning/alarmDataList",
        method: "post",
        params: {
          dvo: this.query.deviceNo,
          alarmType: this.query.alarmType,
          startTime: this.query.queryTime[0],
          endTime: this.query.queryTime[1],
        }
      }).then(res => {
        this.alarmLoading = false
        this.alarmOptions = []
        // 扩展运算符用于数组的浅拷贝，它只会复制数组中的元素的引用，而不是创建新的独立的对象，所以alarmOptions中某个对象的属性值改变，alarmOptionsAll也会变。故不能这么用
        // this.alarmOptions = [{ value: '', label: "全部报警", number: 0 }, ...this.alarmOptionsAll]
        // 可以用JSON.parse() 和 JSON.stringify()
        this.alarmOptions = [{ value: '', label: "全部报警", number: 0 }, ...JSON.parse(JSON.stringify(this.alarmOptionsAll))]
        this.alarmList = []
        let _list: any = [];
        // 如果报警过多则取一个点代替,需要优化
        let aggregation = parseInt(res.data.length / 1000 + '')
        this.alarmList = res.data;
        this.alarmList.forEach((v, i) => {
          if (aggregation === 0 || i % aggregation === 0) {
            // 添加报警点
            let _marker: any = L.marker(L.latLng(v), {
              icon: L.icon({
                iconUrl: this.myRequire('track/alarmPoint.png'),
                iconAnchor: [18, 18]
              }),
            })
            _marker.on('click', function (ev) {
              _this.showPopup(v, "alarmPoint", "报警点")
            });
            _list.push(_marker)
          }
          this.alarmOptions[0].number++;
          let match: any = this.alarmOptions.find(vv => {
            return vv.value === v.alarmType
          })
          if (match) match.number++;
        })
        mapLayer.alarmLayer = L.featureGroup(_list).addTo(map);
      })
    },
    debounce(func) {
      let _time = this.timer
      if (_time) {
        clearTimeout(_time)
      }
      this.timer = setTimeout(function () {
        func.call();
      }, 500)
    },
    querySearchAsync(queryStr) {
      if (queryStr == '') {
        this.searchOptions = [];
        return
      }
      let _this = this;
      _this.loading = true;
      function doSomething() {
        request({
          url: "/comlbs/realtimePositioning/getDeviceInfo",
          method: "post",
          params: {
            companyId: _this.query.companyId,
            numberPlate: queryStr
          }
        }).then(res => {
          _this.loading = false;
          _this.searchOptions = res.data.map(v => {
            return {
              value: v.deviceId,
              label: v.numberPlate,
            }
          })
        })
      }
      _this.debounce(doSomething);
    },
    // 根据设备号时间获取历史轨迹
    getTrackList() {
      let _this = this,
        deviceNo = this.query.deviceNo;
      _this.isPlay && _this.navgControl('stop');
      this.pointsCheck = false;
      // 右上角的存在则先关闭
      for (let key in this.trackToolParam) {
        if (this.trackToolParam[key]) this.trackToolHandle(key);
      }
      if (deviceNo) {
        _this.mapLoading = true;
        getTrackByid(deviceNo, this.query.queryTime[0], this.query.queryTime[1]).then(response => {
          _this.mapLoading = false;
          if (response.code == 200) {
            //数据初始化
            _this.passPointIndex = 0;
            _this.timeInfoList = [];
            nodeIndex = [];
            _this.dealAllList = response.data;

            //地图图层清除
            for (let key in mapLayer) {
              if (mapLayer[key]) {
                map.removeLayer(mapLayer[key]);
                mapLayer[key] = null;
              }
            }
            //初始化
            this.totalTime = "00:00:00"
            this.switchValue = true

            //判断是否有测距测面图层数据
            this.$refs.myMapTool.measuregroup?.clearLayers();

            if (_this.dealAllList.length > 0) {
              // 大数据不一定上传行驶里程，全部使用前端计算，后期存在行驶里程直接隐藏这段代码
              _this.dealAllList[0].totalKm = 0;
              for (let i = 1; i < _this.dealAllList.length; i++) {
                let curPoint = _this.dealAllList[i], lastPoint = _this.dealAllList[i - 1];
                // 这里四舍五入主要是解决js计算的问题    
                _this.dealAllList[i].totalKm = Math.round(curPoint.distance + lastPoint.totalKm * 1000) / 1000
              }
              allList = _this.dealAllList;
              _this.dealWithInfo();
            } else {
              _this.closePop()
              _this.$message({
                type: 'error',
                showClose: true,
                duration: "2000",
                message: '暂无轨迹数据！'
              });
            }
          }
        }).catch(e => {
          _this.mapLoading = false;
        })
      } else {
        _this.$message({
          type: 'error',
          showClose: true,
          duration: "2000",
          message: "请输入车牌号"
        });
      }
    },
    //处理数据
    dealWithInfo() {
      let firstPoint = allList[0], lastPoint = allList[allList.length - 1];
      this.trackStatistics = {
        averageSpd: 0,
        maxSpd: 0,
        totalKm: lastPoint.totalKm,
        driveTime: "00:00:00",
        stopTime: "00:00:00",
        startTime: firstPoint.gdt,
        endTime: lastPoint.gdt,
        count: allList.length
      }

      //判断逻辑：找到一系列连续为0的点合并为一个停留点
      for (let i = 0; i < allList.length; i++) {
        if (this.trackStatistics.maxSpd < allList[i].spd) { this.trackStatistics.maxSpd = allList[i].spd }

        if (allList[i].spd == 0) {
          let j = i + 1;
          for (; j < allList.length; j++) {
            if (allList[j].spd != 0) {
              break;
            }
          }
          if (j == allList.length) j--
          let startT = dayjs(allList[i].gdt);
          let endT = dayjs(allList[j].gdt);
          let interval = endT.diff(startT, 'seconds');
          //间隔时间大于判定时间
          if (interval > stopTime * 60) {
            nodeIndex.push(i, j);
          }
          i = j;
        }
      }

      //如果停留indexlist最后一项不是刚好停留，则加入最后一个index点号；
      if (nodeIndex[nodeIndex.length - 1] !== allList.length - 1 || nodeIndex.length == 0)
        nodeIndex.push(allList.length - 1);

      let FstopOrDrive;
      if (nodeIndex[0] == 0) {//如果等于0说明开局就是停留，存储的就是停留-行驶的循环
        FstopOrDrive = 'stop'
      } else {//如果不等于0说明开局就是开车，需要在开头加一个0的index
        FstopOrDrive = 'drive'
        nodeIndex.unshift(0)
      }

      let stopTimeCaculate = 0, driveTimeCaculate = 0;
      //根据暂停段的index添加timeline流程
      for (let j = 0; j < nodeIndex.length - 1; j++) {
        let before = nodeIndex[j];
        let next = nodeIndex[j + 1];
        let diffSecond = dayjs(allList[next].gdt).diff(dayjs(allList[before].gdt), 'seconds')
        let obj: any = {
          startT: allList[before].gdt,
          endT: allList[next].gdt,
          startIndex: before,
          endIndex: next,
          startPlace: allList[before].location,
          endPlace: allList[next].location,
          action: 'stop',
          diffSecond: diffSecond,
          interval: this.getStrTime(diffSecond).interval,
          hhmmss: this.getTime(diffSecond),
          totalKm: (allList[next].totalKm - allList[before].totalKm).toFixed(3)
        }
        if (FstopOrDrive == 'stop') {
          //奇数段是停留，偶数段是行驶
          obj.action = j % 2 == 0 ? "stop" : "drive";
        } else if (FstopOrDrive == 'drive') {
          //奇数段是行驶，偶数段是停留
          obj.action = j % 2 !== 0 ? "stop" : "drive";
        }
        obj.actionStr = obj.action == "stop" ? "停留" : "移动";

        if (obj.action == "stop") {
          stopTimeCaculate += obj.diffSecond
          obj.totalKm = 0.00
        } else {
          driveTimeCaculate += obj.diffSecond
        }
        this.timeInfoList.push(obj);
      }
      this.trackStatistics.driveTime = this.getTime(driveTimeCaculate);
      this.trackStatistics.stopTime = this.getTime(stopTimeCaculate);

      this.trackStatistics.averageSpd = Number(driveTimeCaculate) !== 0 ? (Number(this.trackStatistics.totalKm) / Number(driveTimeCaculate) * 3600).toFixed(1) : 0
      this.initRoad();
    },
    initRoad() {
      let _this = this;
      // 轨迹
      let startPoint = allList[0], endPoint = allList[allList.length - 1];
      // 添加起点
      mapLayer.sPointLayer = L.marker(startPoint, {
        icon: L.icon({
          iconUrl: this.myRequire('track/startIcon.png'),
          iconSize: [29, 35],
          iconAnchor: [15, 18]
        }),
      }).addTo(map).on('click', function (ev) {
        _this.showPopup(startPoint, "trackPoint", "起点")
      });

      // 添加终点
      mapLayer.ePointLayer = L.marker(endPoint, {
        icon: L.icon({
          iconUrl: this.myRequire('track/endIcon.png'),
          iconSize: [29, 35],
          iconAnchor: [15, 18]
        }),
      }).addTo(map).on('click', function (ev) {
        _this.showPopup(endPoint, "trackPoint", "终点")
      });

      // 这段轨迹总时间，hh:mm:ss
      this.totalTime = this.getTime((endPoint.gte - startPoint.gte) / 1000);

      //总的轨迹线
      mapLayer.routeLine = L.polyline(allList, {
        weight: 4,
        color: document.documentElement.style.getPropertyValue('--el-color-primary')
      }).addTo(map);
      map.fitBounds(mapLayer.routeLine.getBounds());

      this.trackPlayInit(0);
    },
    getPopImg(point) {
      let _src, _backSrc;
      _backSrc = this.myRequire("map/pop/driving.png");
      _src = this.myRequire('equipment/' + selectEquip.objIcon + '.png')

      return L.divIcon({
        html: `<img src="${_src}" class='map-icon'/>` +
          `<img src="${_backSrc}" class='map-icon-back' style="transform:rotate(${point.dre - 45}deg)"/>`,
      })
    },
    //初始化小车需要跑的轨迹
    trackPlayInit(beforeIndex) {
      // 如果跨过前置方法需要清除这两
      if (mapLayer.realRouteLine) {
        map.removeLayer(mapLayer.realRouteLine)
      }
      newLatlngs = allList.slice(0, beforeIndex + 1)

      mapLayer.realRouteLine = L.polyline(newLatlngs, {
        weight: 4,
        color: '#2E8B57'
      }).addTo(map);

      let points = allList.slice(beforeIndex), _this = this;

      if (mapLayer.navgtr) {
        map.removeLayer(mapLayer.navgtr);
      }

      let _icon = this.getPopImg(points[0])
      mapLayer.navgtr = L.Marker.movingMarker(points, 1000 / this.times * points.length, {
        rotationOrigin: 'center center',
        icon: _icon,
        zIndexOffset: 20,
        rotate: false,
        movingBack: updateRealLine
      }).addTo(map).on('click', function (ev) {
        _this.switchValue = !_this.switchValue;
        _this.MapPopContent.getPopData({
          companyName: selectEquip?.companyName,
          gpsDateTime: points[_this.nowCarPointIndex].gdt,
          location: points[_this.nowCarPointIndex].location,
          totalKm: points[_this.nowCarPointIndex].totalKm,
          numberPlate: selectEquip?.numberPlate,
          spd: points[_this.nowCarPointIndex].spd,
          vehicleStatus: selectEquip?.vehicleStatus,
          satelliteCount: points[_this.nowCarPointIndex].satelliteCount,
          imgURL: selectEquip?.vehiclePic.length ? selectEquip?.vehiclePic[0].path : null,
        });
      }).bindPopup(this.MapPopContent.$el, {
        maxWidth: 'unset',
        closeButton: false,
      }).setLatLng(points[0]).openPopup();


      // 绘制已行走轨迹线
      function updateRealLine(index) {
        _this.nowCarPointIndex = index
        let bounds = map.getBounds();
        let _point = points[index]
        //小车保持在视野范围内
        if (_point.lng > bounds._northEast.lng || _point.lat > bounds._northEast.lat || _point.lng < bounds._southWest.lng || _point.lat < bounds._southWest.lat) {
          map.flyTo({ lng: _point.lng, lat: _point.lat }, map.getZoom(), { animate: false })
        }
        mapLayer.navgtr.setIcon(_this.getPopImg(_point))
        if (_this.switchValue) {
          _this.MapPopContent.getPopData({
            companyName: selectEquip?.companyName,
            gpsDateTime: _point.gdt,
            location: _point.location,
            totalKm: _point.totalKm,
            numberPlate: selectEquip?.numberPlate,
            spd: _point.spd,
            vehicleStatus: selectEquip?.vehicleStatus,
            satelliteCount: _point.satelliteCount,
            imgURL: selectEquip?.vehiclePic.length ? selectEquip?.vehiclePic[0].path : null,
          });
        }
        newLatlngs.push(_point)
        mapLayer.realRouteLine.setLatLngs(newLatlngs)
        _this.sliderVal = beforeIndex + index + 1;
        //结束以后的方法
        if (index == points.length - 1) {
          _this.isPlay = false;
          isPlayEnd = true;
        }
      }
      updateRealLine(0);
      // 判断设备是否需要行走
      if (this.isPlay) mapLayer.navgtr?.start();
      // 判断气泡是否打开
      this.updateInfoWindos();
    },
    // 开始、暂停、继续等操作
    navgControl(playStatus) {
      if (allList.length == 0) return
      if (playStatus == "start") {
        if (allList.length === 1) {
          this.$modal.msgWarning("该段数据全程停留,不支持播放");
          return
        }
        if (isPlayEnd) this.trackPlayInit(0);
        mapLayer.navgtr?.start();
        this.isPlay = true;
        isPlayEnd = false;
      } else if (playStatus == "stop") {
        mapLayer.navgtr?.stop();
        this.sliderVal = 0;
        this.isPlay = false;
        isPlayEnd = true;
        this.trackPlayInit(0);
      } else if (playStatus == "pause") {
        mapLayer.navgtr?.pause();
        this.isPlay = false;
      }
    },
    //拖拽滚动条执行方法
    sliderChange(val) {
      let _this = this, beforePassedIndex = _this.sliderVal - 1;
      if (allList.length == 0) return
      _this.trackPlayInit(beforePassedIndex);
    },
    //控制窗体显隐
    updateInfoWindos(val) {
      if (allList.length == 0) return
      if (this.switchValue) {
        let _point = allList[this.sliderVal - 1]
        this.MapPopContent.getPopData({
          companyName: selectEquip?.companyName,
          gpsDateTime: _point.gdt,
          location: _point.location,
          totalKm: _point.totalKm,
          numberPlate: selectEquip?.numberPlate,
          spd: _point.spd,
          vehicleStatus: selectEquip?.vehicleStatus,
          satelliteCount: _point.satelliteCount,
          imgURL: selectEquip?.vehiclePic.length ? selectEquip?.vehiclePic[0].path : null,
        });
        if (mapLayer.navgtr.getPopup()) {
          map.closePopup();
          mapLayer.navgtr.setLatLng(_point).openPopup();
        }
      } else {
        map.closePopup()
      }
    },
    closePop() {
      this.switchValue = false;
      map.closePopup();
    },
    // 修改速度以后的方法
    changeSpd() {
      if (allList.length == 0) return
      this.trackPlayInit(this.sliderVal - 1);
    },
    showPopup(_data, type, title) {
      if (this.switchValue) {
        // 当查看其他点位详情的时候需要关闭小车的气泡
        this.switchValue = false
      }
      let obj: any = {
        title: title
      }
      let indexPoint
      allList.forEach((v, i) => {
        if (_data.lat == v.lat && _data.lng == v.lng) indexPoint = i
      })
      if (type == "trackPoint") {
        obj.numberPlate = selectEquip?.numberPlate
        obj.companyName = selectEquip?.companyName
        obj.vehicleStatus = selectEquip?.vehicleStatus
        obj.spd = _data.spd
        obj.mie = _data.mie
        obj.totalKm = _data.totalKm
        obj.satelliteCount = _data.satelliteCount
        obj.gpsDateTime = _data.gdt
        obj.location = _data.location
      } else if (type == "parkPoint") {
        obj.startPlace = _data.startPlace
        obj.interval = _data.interval
        obj.startT = _data.startT
        obj.endT = _data.endT
      } else if (type == "alarmPoint") {
        obj.alarmTypeName = _data.alarmTypeName
        obj.address = _data.address
        obj.endTime = _data.endTime
        obj.startTime = _data.startTime
        obj.duration = _data.duration
        obj.spd = _data.spd
      }
      this.MapPopContent.getPopData(obj, type)
      L.popup({
        maxWidth: 'unset',
        closeButton: false
      }).setLatLng(_data).setContent(this.MapPopContent.$el).openOn(map);
    },
    //展示轨迹点
    showTrachPoints() {
      let _this = this;
      function _openPopup(e) {
        _this.showPopup(e.layer.attribution, "trackPoint", "轨迹点")
      }
      if (this.pointsCheck) {
        if (mapLayer.trackPointsLayer) return;
        addLotsOfPoints(map, allList, _openPopup).then(layer => {
          mapLayer.trackPointsLayer = layer
        })
      } else {
        if (mapLayer.trackPointsLayer) {
          mapLayer.trackPointsLayer.removeFrom(map);
          mapLayer.trackPointsLayer = null;
          if (!_this.switchValue) map.closePopup();
        }
      }
    },
    //展示某段轨迹
    showPeriodTrac(data: any, index) {
      if (mapLayer.trackShowLine) {
        map.removeLayer(mapLayer.trackShowLine);
      }
      this.tableActive = this.tableActive == index ? -1 : index
      if (data.action == 'stop') {
        let _point = allList[data.endIndex]
        this.showPopup({ ...data, lng: _point.lng, lat: _point.lat }, "parkPoint", "停留点")
        map.flyTo({ lng: _point.lng, lat: _point.lat }, 18, { animate: false })
      } else if (data.action == "drive") {
        mapLayer.trackShowLine = L.polyline(allList.slice(data.startIndex, data.endIndex), { color: 'red' }).addTo(map);
        map.fitBounds(mapLayer.trackShowLine.getBounds());
      }
    },
    // 格式化时间(秒转00:00:00)
    getTime(sTime: any) {
      let ss;
      let mm: any = "00";
      let hh: any = "00";
      if (sTime > 59) {
        let s = parseInt(sTime % 60 + '');
        ss = s > 9 ? s : "0" + s;
        let mTime = parseInt(sTime / 60 + '');
        if (mTime > 59) {
          let m = mTime % 60;
          mm = m > 9 ? m : "0" + m;
          hh = parseInt(mTime / 60 + '') > 9 ? parseInt(mTime / 60 + '') : "0" + parseInt(mTime / 60 + '');
        } else {
          mm = mTime > 9 ? mTime : "0" + mTime;
        }
      } else {
        sTime = parseInt(sTime)
        ss = sTime > 9 ? sTime : "0" + sTime;
      }
      return hh + ":" + mm + ":" + ss;
    },
    // 格式化时间(5时45分46秒)
    getStrTime(sTime: any) {
      let ss;
      let mm: any = "00";
      let hh: any = "00";
      if (sTime > 59) {
        let s = sTime % 60;
        ss = s;
        let mTime = parseInt(sTime / 60 + '');
        if (mTime > 59) {
          let m = mTime % 60;
          mm = m > 9 ? m : m;
          hh = parseInt(mTime / 60 + '');
        } else {
          mm = mTime;
        }
      } else {
        ss = sTime;
      }
      let timeList = "";
      if (hh != '00')
        timeList += hh + "时";
      if (mm != '00')
        timeList += mm + "分";
      if (ss != '00')
        timeList += ss + "秒";
      return { interval: timeList, hh: hh, mm: mm, ss: ss };
    },
    // 判断浏览器是否回到当前页面
    visibilityChange(evt, hidden) {
      if (hidden === false) {//回当前页面
        this.lastPlayStatus && this.navgControl('start')
      } else {//切换到别的页面
        this.lastPlayStatus = this.isPlay;
        this.isPlay && this.navgControl('pause')
      }
    },
  },
  activated() {
    map && map.invalidateSize(false)
    this.visibilityChange(null, false)
  },
  deactivated() {
    this.visibilityChange(null, true)
  },
};
</script>
  
<style scoped lang='scss'>
.app-container {
  margin: 0;
  width: 100%;
  height: 100%;
}


:deep(.leaflet-popup) {
  color: #333;

  .title {
    font-weight: bold;
    font-size: 14px;
  }

  .text {
    font-size: 13px;
    width: 270px;
    margin-top: 6px;
  }
}

#TT_container {
  position: absolute;
  height: 100%;
  width: 100%;
  z-index: 0;
}

.track-tool-right {
  position: absolute;
  top: 10px;
  right: 10px;
  height: 32px;
  background-color: #fff;
  color: #223355;
  filter: drop-shadow(0px 12px 20px rgba(68, 77, 113, 0.3));
  display: flex;
  align-items: center;
  border-radius: 4px;
  font-size: 14px;
  padding: 4px;

  .new-window-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    width: 110px;
  }

  .tool-btn {
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    margin: 0 2px;
    cursor: pointer;
    border-radius: 4px;

    i {
      margin-right: 4px;
      color: #6B7A99;
    }

    &:hover,
    &.active {
      color: #fff;
      background-image: linear-gradient(to right, var(--el-color-primary), var(--el-color-primary-light-2));
      cursor: pointer;

      i {
        color: #fff;
      }
    }
  }
}


.track-tool {
  position: absolute;
  top: 10px;
  left: 476px;
  filter: drop-shadow(0px 12px 20px rgba(68, 77, 113, 0.3));
}

:deep(.el-tabs__content) {
  height: calc(100% - 55px);

  .el-tab-pane {
    height: 100%;
    display: flex;
  }
}

.search-dom {
  position: absolute;
  top: 10px;
  left: 10px;

  li {
    filter: drop-shadow(0px 12px 20px rgba(68, 77, 113, 0.3));
    background: #fff;
    padding: 12px;
    border-radius: 8px;

    &:first-of-type {
      margin-bottom: 10px;
    }
  }

  :deep(.track-timepicker) {
    .el-range-input {
      color: var(--el-color-primary);
    }
  }

  .timeText {
    color: var(--el-color-primary);
    display: inline-block;
    min-width: 40px;
    text-align: center;
    font-size: 14px;
  }

  .trackControl-top {
    display: flex;
    align-items: center;
    padding-left: 8px;
    margin-bottom: 4px;
  }

  .trackControl-mid {
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--el-color-primary);

    .svg-icon {
      cursor: pointer;
      font-size: 20px;
    }

    .slider {
      width: 200px;
      display: inline-flex;
      margin: 5px 15px;
    }
  }

  .background-dom {
    background: #fff;
    border-radius: 6px;
    height: 44px;
    width: 432px;
    display: flex;
    align-items: center;
    box-sizing: border-box;

    .track-timepicker {
      width: 100%;

      :deep(.el-range-input) {
        color: var(--el-color-primary);
      }
    }
  }

  .search-btn {
    font-size: 14px;
    margin-left: auto;
    padding: 8px;
  }

  .search-title {
    display: inline-block;
    color: #223355;
    font-size: 14px;
  }

  .search-input {
    width: 130px;
    display: inline-block;

    :deep(.el-input__inner) {
      font-size: 14px;
      color: var(--el-color-primary);
    }
  }
}

.track-report-form {
  position: absolute;
  bottom: 10px;
  right: 10px;
  width: 1000px;
  height: 368px;
  background-color: #fff;
  box-shadow: 0 0 20px 8px #ccc, 0px 8px 20px 0px #11172414;
  border-radius: 4px;

  .bot-body {
    height: calc(100% - 34px);
    width: 100%;
    padding: 8px 16px;
    box-sizing: border-box;
    display: inline-flex;

    .left-nav {
      width: 150px;
      margin-right: 16px;
      height: 100%;
      overflow: auto;

      li {
        line-height: 32px;
        width: 100%;
        color: #6B7A99;
        font-size: 14px;
        background-color: var(--el-color-primary-light-9);
        padding: 0 8px;
        box-sizing: border-box;
        margin-top: 4px;
        cursor: pointer;
        border: 1px solid transparent;
        display: flex;

        .label-str {
          display: inline-block;
          width: calc(100% - 36px);
        }

        .number-str {
          display: inline-block;
          width: 36px;
          text-align: right;
        }

        &:first-of-type {
          margin-top: 0;
        }

        &.active {
          color: var(--el-color-primary);
          border-color: var(--el-color-primary-light-4);
        }
      }
    }

    .top-nav {
      margin-bottom: 8px;

      li {
        color: #6B7A99;
        width: 92px;
        height: 32px;
        border: 1px solid #E9ECF2;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        box-sizing: border-box;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;

        margin-right: 4px;

        &:hover,
        &.active {
          color: var(--el-color-primary);
          border-color: var(--el-color-primary);
        }
      }
    }
  }

  .drive-tab {
    width: 8px;
    height: 8px;
    background-color: #11C79B;
    border-radius: 100%;
    display: inline-block;
    margin-right: 4px;
  }

  .stop-tab {
    width: 8px;
    height: 8px;
    background-color: #FF9900;
    border-radius: 100%;
    display: inline-block;
    margin-right: 4px;
  }
}

.top-dom {
  background-image: linear-gradient(to right, var(--el-color-primary), var(--el-color-primary-light-2));
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 34px;
  font-size: 14px;
  padding: 0 16px;
  border-radius: 4px 4px 0 0;

  .right-dom {
    display: flex;
    align-items: center;
    margin-left: auto;

    .export-btn {
      line-height: 20px;
      padding: 2px 12px;
      color: #fff;
      border-radius: 2px;
      margin-right: 10px;
      cursor: pointer;
      border: 1px solid #fff;
    }
  }

  .iconfont {
    margin-right: 8px;
  }

  .el-icon {
    margin-left: auto;
    cursor: pointer;
  }
}

.track-tool-list {
  position: absolute;
  top: 55px;
  right: 10px;
  width: 390px;
  filter: drop-shadow(0px 12px 20px rgba(68, 77, 113, 0.3));
  font-size: 14px;

  >div {
    margin-bottom: 8px;
    border-radius: 10px;
    box-shadow: 0px 8px 20px 0px #11172414;
  }

  .statistics-line-dom {
    background-color: #fff;
    box-sizing: border-box;

    .content {
      color: #6B7A99;
      display: flex;
      flex-wrap: wrap;
      line-height: 26px;
      padding: 5px 15px;

      .statistics-info {
        >span:first-of-type {
          min-width: 60px;
          display: inline-block;
          text-align: right;
        }

        width: 180px;
      }
    }
  }

  .speed-line-dom {
    height: 200px;
    background-color: #fff;
    box-sizing: border-box;

    .content {
      width: 100%;
      height: calc(100% - 30px);
    }
  }
}


.fence-form {
  position: absolute;
  left: 10px;
  bottom: 10px;
  background-color: #FFF;

  .dialog-footer {
    text-align: right;
    margin-bottom: 16px;
    margin-right: 16px;
  }
}

:deep(.leaflet-div-icon) {
  background: transparent;
  border-color: transparent;
}

:deep(.el-table-v2__empty) {
  top: 0;
}

.img-dom {
  float: right;
  border: 1px solid black;
  height: 165px;
  width: 224px;

  .noImage {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  &:first-of-type {
    border-bottom: 0;
  }

  &:last-of-type {
    border-top: 0;
  }

  img {
    width: 100%;
    height: 100%;
  }
}
</style>
  